from abc import ABC, abstractmethod
from os import PathLike
import subprocess
import logging


class Agent(ABC):
    @abstractmethod
    def command(self, command: str) -> str:
        """Enter a command to the game and return the feedback
        Args:
            command: The command to input
        Return:
            The feedback from game
        """
        pass


class ZorkIAgent(Agent):
    def __init__(self, path, restore_flag: bool, save_flag: bool) -> None:
        super().__init__()
        self._popen = subprocess.Popen(
            path,
            shell=False,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            bufsize=0,
            start_new_session=True,
        )
        self._save_flag = True
        self._restore_flag = True
        if self._restore_flag:
            self.command("restore")
            print("Game has restored!")

    def __del__(self):
        if self._save_flag:
            print(self.command("save"))
            print("Game has saved!")
        self._popen.kill()

    def get_output(self) -> str:
        buf = []
        new_line_flag = False
        while True:
            r = self._popen.stdout.read(1).decode()

            if new_line_flag and r == ">":
                break
            buf.append(r)
            new_line_flag = True if r == "\n" else False
        return "".join(buf)

    def command(self, command: str) -> str:
        self._popen.stdin.write(bytes(command + "\n", encoding="utf-8"))

        buf = self.get_output()

        return buf


if __name__ == "__main__":
    agent = ZorkIAgent("zork", True, True)
    print(agent.get_output())

    while True:
        input_str = input(">>>").strip()
        if input_str:
            output_str = agent.command(input_str)
            print(output_str)
